import {esri} from "../api/esriAPI";
import {arcgisEventBus} from "../eventBus/arcgisEventBus";

/**
 * view逻辑操作-----------业务开发中，不允许直接调用它，如果需要，需要通过工具中向外提供接口
 * @class
 * */
export const ManageView = class {
  _mapDOM = null;//整个地图创建的DOM对象
  mapId = null;//mapId
  _mapStatus = true;//地图的状态,2D:true,3D:false
  _bind2D_3D = true;//是否绑定2D和3D
  _dom_2D = null;//2D的DOM对象
  _dom_3D = null;//3D的DOM对象
  _mapView = null;//mapView对象
  _sceneView = null;//mapView对象
  _map = null;//2D和3D公用的Map对象
  /**
   * 构造函数
   */
  constructor(mapId) {
    this.mapId = mapId;
    this._mapDOM = document.getElementById(mapId);
  }

  /**
   * 申请MapView对象，如果该对象存在，不在创建新的对象
   * @param {Object} map arcgis的Map对象
   * @returns {Object} arcgis的MapView对象
   */
  applyMapView(mapConfig) {
    let mapId = this.mapId;
    let container = mapId + "_2D";
    if (this._mapView) {
      this.switchView(true);
      return this._mapView
    }
    let map = this._applyMap(mapConfig);
    this._dom_2D = createDOM(this._mapDOM, container);
    this._mapView = new esri.MapView({map, container});
    this._mapView.ui.components = ["zoom"]; //只保留某些
    this.switchView(true)
    return this._mapView;
  }

  /**
   * 申请SceneView对象，如果该对象存在，不在创建新的对象
   * SceneView支持全局场景中的以下坐标系：WGS84或WebMercator
   * @param {Object} map arcgis的Map对象
   * @returns {Object} arcgis的SceneView对象
   */
  applySceneView(mapConfig) {
    let mapId = this.mapId;
    let container = mapId + "_3D";
    if (this._sceneView) {
      this.switchView(false);
      return this._sceneView
    }
    let map = this._applyMap(mapConfig);
    this._dom_3D = createDOM(this._mapDOM, container);
    this._sceneView = new esri.SceneView({map, container,viewingMode:"local"});
    // this._sceneView.ui.components = ["attribution", "navigation-toggle", "compass", "zoom"]; //去掉一些其他的UI
    this.switchView(false)
    return this._sceneView;
  }

  /**
   * 飞到指定的xy位置，
   * @param x x坐标
   * @param y y坐标
   * @param zoomOrZ 2维是zoom,3维是z  默认值：如果是3维，将飞到z=30000米的高空，如果是2维，将飞到zoom等于12的位置
   */
  flyToXY(x, y, zoomOrZ) {
    if (this.getMapStatus()) {
      this.flyToPoint2D(x, y, zoomOrZ || 12);
    } else {
      this.flyToPosition3D(x, y, zoomOrZ || 30000);
    }
  }

  /**
   * 三维飞到指定位置
   * @param {Number} x x坐标
   * @param {Number} y y坐标
   * @param {Number} z 海拔（米）   默认值：当前的高度
   * @param {Number} fov 相机的视野以度为单位。 默认值：当前的视野
   * @param {Number} heading 相机的heading以度为单位。当北方是屏幕的顶部时，heading为零。它随着视图顺时针旋转而增加。角度始终在0到360度之间归一化 ，默认值:当前的视角
   * @param {Number} tilt 当从相机位置向下投射时，相机相对于表面的倾斜度。当垂直向下看表面时倾斜为零，当相机看起来与表面平行时，倾斜度为90度。
   */
  flyToPosition3D(x, y, z, fov, heading, tilt) {
    let view = this._sceneView;
    var camera = view.camera.clone();
    camera.fov = fov || camera.fov;
    camera.heading = heading || camera.heading;
    camera.tilt = tilt || camera.tilt;
    camera.position = {
      x,
      y,
      z: z || camera.position.z
    }
    console.log("flyToPosition3D", x, y, camera.position.z, camera.fov, camera.heading, camera.tilt)
    view.goTo(camera);
  }

  /**
   * 2维飞到指定位置
   * @param {Number} x x坐标
   * @param {Number} y y坐标
   * @param {Number} zoom 缩放比例
   * @param {Object | Number} spatialReference 坐标参考系，默认:底图参考系，允许直接书写参考系数值，也可以书写完整的参考对象
   */
  flyToPoint2DByXY(x, y, zoom, spatialReference) {
    let view = this._mapView;
    spatialReference = spatialReference || view.spatialReference;
    if (typeof spatialReference != "object") {
      spatialReference = {wkid: spatialReference}
    }
    zoom = zoom || view.zoom;
    //isWebMercator
    //latestWkid
    console.log("flyToPoint", x, y, spatialReference, zoom)
    let center = new esri.Point({x, y, spatialReference});
    view.goTo({center, zoom});
  }

  /**
   * 2维飞到指定经纬度位置
   * @param {Number} longitude 经度
   * @param {Number} latitude 纬度
   * @param {Number} zoom 缩放比例
   * @param {Object | Number} spatialReference 坐标参考系，默认:底图参考系，允许直接书写参考系数值，也可以书写完整的参考对象
   */
  flyToPoint2D(longitude, latitude, zoom, spatialReference) {
    let view = this._mapView;
    spatialReference = spatialReference || view.spatialReference;
    if (typeof spatialReference != "object") {
      spatialReference = {wkid: spatialReference}
    }
    zoom = zoom || view.zoom;
    console.log("flyToPoint", longitude, latitude, spatialReference, zoom)
    let center = new esri.Point({longitude, latitude, spatialReference});
    view.goTo({center, zoom});
  }

  /**
   * 移除MapView对象，同时删除DOM节点
   */
  removeMapView() {
    let {_mapDOM, _dom_2D} = this;
    if (_dom_2D) {
      this._mapView = null;
      _mapDOM.removeChild(_dom_2D);
      this._dom_2D = null;
    }
  }

  /**
   * 移除SceneView对象，同时删除DOM节点
   */
  removeSceneView() {
    let {_mapDOM, _dom_3D} = this;
    if (this._sceneView) {
      this._sceneView = null;
      _mapDOM.removeChild(_dom_3D);
      this._dom_3D = null;
    }
  }

  /**
   * 获得地图的状态
   * @returns {boolean} 2D:true | 3D :false
   */
  getMapStatus() {
    return this._mapStatus;
  }

  /**
   * 获得地图的Map对象（会根据当前的状态，分别给2D/3D的map对象）
   * @returns {*} arcgis的map对象
   */
  getMap() {
    return this._map;
  }

  /**
   * 根据2D/3D状态，获得对应view对象
   * @returns {Object} arcgis的 (MapView对象|SceneView)
   */
  getView() {
    return this.getMapStatus() ? this.getMapView() : this.getSceneView();
  }

  /**
   * 获得mapView对象
   * @returns {Object} arcgis的 MapView对象
   */
  getMapView() {
    return this._mapView;
  }

  getMapViewDOM() {
    return this._dom_2D;
  }

  getSceneViewDOM() {
    return this._dom_3D;
  }

  getDOM() {
    return this.getMapStatus() ? this.getMapViewDOM() : this.getSceneViewDOM();
  }

  /**
   * 获得SceneView对象
   * @returns {Object} arcgis的 SceneView
   */
  getSceneView() {
    return this._sceneView;
  }

  /**
   * 是否绑定2D/3D的联动状态
   * @param {Boolean} status 是否绑定2D/3D的联动状态
   */
  bind2D_3D(status) {
    this._bind2D_3D = status;
  }

  /**
   * 切换2D/3D
   * @param {Boolean} status 是否是2D  2D:true,3D:false
   */
  switchView(status) {
    this._mapStatus = status;
    if (this._mapView && this._sceneView) {
      if (this._bind2D_3D) {
        companion(status, this._mapView, this._sceneView);
      }
      //地图切换，发送事件总线
      arcgisEventBus.bus.$emit(arcgisEventBus.SWITCH_2D_3D + this.mapId, status);
      let showDom, hideDom;
      if (status) {
        showDom = this._dom_2D;
        hideDom = this._dom_3D;
      }
      else {
        showDom = this._dom_3D;
        hideDom = this._dom_2D;
      }
      showDom && (showDom.style.width = "100%");
      hideDom && (hideDom.style.width = "0")
    }
  }

  /**
   * 添加地图的2D/3D切换的监听事件
   * @param {Function} fn 事件回调的方法
   */
  addMapSwitchEvent(fn) {
    arcgisEventBus.bus.$on(arcgisEventBus.SWITCH_2D_3D + this.mapId, fn);
  }

  /**
   * 移除地图的2D/3D切换的监听事件
   * @param {Function} fn 事件回调的方法
   */
  removeMapSwitchEvent(fn) {
    arcgisEventBus.bus.$off(arcgisEventBus.SWITCH_2D_3D + this.mapId, fn)
  }

  _applyMap(mapConfig) {
    if (this._map) {
      return this._map;
    }
    if (mapConfig && mapConfig.baseLayers) {
      mapConfig.basemap = new esri.Basemap({baseLayers: mapConfig.baseLayers});
    }
    let map = new esri.Map(mapConfig)
    this._map = map;
    return map;
  }
}


/**
 * 构建地图渲染的对象
 * @private
 * @param parentNode 父级的DOM节点
 * @param nodeId 子节点ID
 * @returns {Object} 该节点的DOM对象
 */
function createDOM(parentNode, nodeId) {
  if (!parentNode.style.position) {
    parentNode.style.position = "relative";
  }
  var node = document.createElement("div")
  node.id = nodeId
  node.style.width = "100%";
  node.style.height = "100%";
  node.style.position = "absolute";
  node.style.top = "0";
  node.style.left = "0";
  parentNode.appendChild(node);
  return node;
}

/**
 * 地图切换跟随----------------切换的时候触发
 * @private
 * @param {String} mapId 地图的mapId
 * @param {Boolean} is2D 2D/3D状态
 */
function companion(status, mapView, sceneView) {
  if (status) {
    mapView.viewpoint = sceneView.viewpoint;
  } else {
    sceneView.goTo(mapView.extent, {
      duration: 200,
      easing: "out-quint"
    });
  }
}
